//
// Created by zy-li14 on 16-9-24.
//

#include "include/ActMaker/ActMaker.h"
#include <iostream>
#include <thread>
#include <atomic>
#include <sdk/sdk.h>
using SDK::PPlayerInfo;


using namespace std;
template <const char* funcName, typename... Types>
bool ActMaker<funcName, Types...>::load(const char* fileName)
{
#ifdef Windows
    dll=LoadLibrary(fileName);
    if (!dll)
    {
        cerr<< "no dll, Get Last Error" << GetLastError() << endl;
		cerr<< fileName << endl;
        return false;
    }
    player_ai=(AiFunction)(GetProcAddress(dll, funcName));
    cerr << (long long)(dll) << "##" << (long long)(GetProcAddress(dll, funcName)) << endl;
    if (!player_ai)
    {
        cerr<< "no ai, Get Last Error" << GetLastError() << endl;
		cerr<< fileName << endl;
        return false;
    }
#else
    dll=dlopen(fileName,RTLD_NOW);
    if (!dll)
    {
        cerr<< dlerror() << endl;
    }
    player_ai = reinterpret_cast<AiFunction>(dlsym(dll, funcName));
    if ( !player_ai)
    {
        cerr << "Load AI func Failed!" << endl;
        cerr<< dlerror() << endl;
    }
#endif//_AC_WIN_
    return true;
}

template <const char* funcName, typename... Types>
ActMaker<funcName, Types...>::~ActMaker()
{
    if ( dll )
#ifdef Windows
        FreeLibrary(dll);
#else
        dlclose(dll);
#endif//_AC_WIN_
}

template <const char* funcName, typename... Types>
bool ActMaker<funcName, Types...>::getCommand(Types... args)
{
    using namespace std::chrono;
    int signal = 0;
    std::string funcNameStr(funcName);
    if (funcNameStr == "player_ai") {
        auto run = [&signal, &args..., this]() {
            try {
                player_ai(args...);
            }
            catch (std::exception &e) {
                std::cerr << e.what() << std::endl;
                signal = -1;
                return;
            }
            signal = 1;
        };
        thread ai(run);
        auto terminateTime = system_clock::now() + seconds(1);
        while (system_clock::now() < terminateTime && signal == 0);
        ai.detach();
    }
    else {
        try {
            player_ai(args...);
        }
        catch (std::exception &e) {
            std::cerr << e.what() << std::endl;
        }
    }
    return true;
}

template <const char* funcName, typename... Types>
ActMaker<funcName, Types...>::ActMaker(const char *file_name) : AbstractActMaker<Types...>(){
    this->load(file_name);
}

extern char const player_aiString[] = "player_ai";
extern char const feedback_aiString[] = "feedback_ai";

template class ActMaker<player_aiString, const PlayerInfo &, Commands &, SDK::PShowInfo &>;
template class ActMaker<feedback_aiString, vector<SDK::PPlayerInfo::HumanOrder>, SDK::PShowInfo&>;
